package com.example.teaching_server.service;

import com.example.teaching_server.dto.CreateNoticeRequest;
import com.example.teaching_server.dto.NoticeDTO;
import com.example.teaching_server.dto.NoticeRequest;
import com.example.teaching_server.entity.*;
import com.example.teaching_server.repository.*;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
@Transactional
public class NoticeService {

    private final NoticeRepository noticeRepository;
    private final NoticeTypeRepository noticeTypeRepository;
    private final NoticeRecipientRepository noticeRecipientRepository;
    private final UserRepository userRepository;  // 使用JPA版本
    private final ClassRepository classRepository;
    private final ScheduleRepository scheduleRepository;

    /**
     * 获取用户收到的通知列表
     */
    @Transactional(readOnly = true)
    public List<NoticeDTO> getReceivedNotices(NoticeRequest request) {
        List<NoticeEntity> notices;

        if (request.getTypeId() != null) {
            notices = noticeRepository.findReceivedNoticesByUserIdAndType(request.getUserId(), request.getTypeId());
        } else {
            notices = noticeRepository.findReceivedNoticesByUserId(request.getUserId());
        }

        return notices.stream()
                .map(notice -> convertToDTO(notice, request.getUserId(), "received"))
                .collect(Collectors.toList());
    }

    /**
     * 获取用户发布的通知列表
     */
    @Transactional(readOnly = true)
    public List<NoticeDTO> getPublishedNotices(NoticeRequest request) {
        List<NoticeEntity> notices;

        if (request.getTypeId() != null) {
            notices = noticeRepository.findByTypeIdAndCreatedByOrderByCreatedAtDesc(
                    request.getTypeId(), request.getUserId());
        } else {
            notices = noticeRepository.findByCreatedByOrderByCreatedAtDesc(request.getUserId());
        }

        return notices.stream()
                .map(notice -> convertToDTO(notice, request.getUserId(), "published"))
                .collect(Collectors.toList());
    }

    /**
     * 获取所有通知类型
     */
    @Transactional(readOnly = true)
    public List<NoticeTypeEntity> getAllNoticeTypes() {
        return noticeTypeRepository.findAllByOrderByTypeNameAsc();
    }

    /**
     * 根据ID获取通知
     */
    @Transactional(readOnly = true)
    public Optional<NoticeEntity> getNoticeById(Long noticeId) {
        return noticeRepository.findById(noticeId);
    }

    /**
     * 创建通知
     */
    public NoticeEntity createNotice(CreateNoticeRequest request, Long createdBy) {
        // 验证通知类型是否存在
        NoticeTypeEntity noticeType = noticeTypeRepository.findById(request.getTypeId())
                .orElseThrow(() -> new RuntimeException("通知类型不存在"));

        // 验证创建者是否存在
        UserEntity creator = userRepository.findById(createdBy)
                .orElseThrow(() -> new RuntimeException("用户不存在"));

        // 验证关联课程是否存在（如果提供了scheduleId）
        if (request.getScheduleId() != null) {
            scheduleRepository.findById(request.getScheduleId())
                    .orElseThrow(() -> new RuntimeException("课程不存在"));
        }

        // 创建通知实体
        NoticeEntity notice = new NoticeEntity();
        notice.setTitle(request.getTitle());
        notice.setTypeId(request.getTypeId());
        notice.setDescription(request.getDescription());
        notice.setContent(request.getContent());
        notice.setScheduleId(request.getScheduleId());
        notice.setCreatedBy(createdBy);
        notice.setCreatedAt(LocalDateTime.now());
        notice.setUpdatedAt(LocalDateTime.now());

        NoticeEntity savedNotice = noticeRepository.save(notice);

        // 创建接收者记录
        createNoticeRecipients(savedNotice.getNoticeId(), request.getRecipients());

        return savedNotice;
    }

    /**
     * 更新通知
     */
    public NoticeEntity updateNotice(Long noticeId, CreateNoticeRequest request, Long userId) {
        // 查找现有通知
        NoticeEntity notice = noticeRepository.findById(noticeId)
                .orElseThrow(() -> new RuntimeException("通知不存在"));

        // 验证权限：只有创建者才能修改
        if (!notice.getCreatedBy().equals(userId)) {
            throw new RuntimeException("没有权限修改此通知");
        }

        // 验证通知类型
        NoticeTypeEntity noticeType = noticeTypeRepository.findById(request.getTypeId())
                .orElseThrow(() -> new RuntimeException("通知类型不存在"));

        // 验证关联课程是否存在（如果提供了scheduleId）
        if (request.getScheduleId() != null) {
            scheduleRepository.findById(request.getScheduleId())
                    .orElseThrow(() -> new RuntimeException("课程不存在"));
        }

        // 更新通知信息
        notice.setTitle(request.getTitle());
        notice.setTypeId(request.getTypeId());
        notice.setDescription(request.getDescription());
        notice.setContent(request.getContent());
        notice.setScheduleId(request.getScheduleId());
        notice.setUpdatedAt(LocalDateTime.now());

        // 删除旧的接收者记录
        noticeRecipientRepository.deleteByNoticeId(noticeId);

        // 创建新的接收者记录
        createNoticeRecipients(noticeId, request.getRecipients());

        return noticeRepository.save(notice);
    }

    /**
     * 删除通知
     */
    public void deleteNotice(Long noticeId, Long userId) {
        // 检查通知是否存在
        NoticeEntity notice = noticeRepository.findById(noticeId)
                .orElseThrow(() -> new RuntimeException("通知不存在"));

        // 验证权限：只有创建者才能删除
        if (!notice.getCreatedBy().equals(userId)) {
            throw new RuntimeException("没有权限删除此通知");
        }

        // 删除接收者记录
        noticeRecipientRepository.deleteByNoticeId(noticeId);

        // 删除通知
        noticeRepository.deleteById(noticeId);
    }

    /**
     * 标记通知为已读
     */
    public void markNoticeAsRead(Long noticeId, Long userId) {
        // 查找用户的接收记录
        Optional<NoticeRecipientEntity> recipientOpt =
                noticeRecipientRepository.findByNoticeIdAndUserId(noticeId, userId);

        if (recipientOpt.isPresent()) {
            NoticeRecipientEntity recipient = recipientOpt.get();
            if (!recipient.getReadStatus()) {
                recipient.setReadStatus(true);
                recipient.setReadAt(LocalDateTime.now());
                noticeRecipientRepository.save(recipient);
            }
        }
    }

    /**
     * 创建通知接收者
     */
    private void createNoticeRecipients(Long noticeId, CreateNoticeRequest.NoticeRecipients recipients) {
        List<NoticeRecipientEntity> recipientList = new ArrayList<>();

        // 处理班级接收者
        if (recipients.getClasses() != null && !recipients.getClasses().isEmpty()) {
            for (Long classId : recipients.getClasses()) {
                // 验证班级是否存在
                classRepository.findById(classId)
                        .orElseThrow(() -> new RuntimeException("班级不存在: " + classId));

                NoticeRecipientEntity recipient = new NoticeRecipientEntity();
                recipient.setNoticeId(noticeId);
                recipient.setRecipientType("class");
                recipient.setTargetId(classId);
                recipient.setReadStatus(false);
                recipient.setCreatedAt(LocalDateTime.now());
                recipientList.add(recipient);
            }
        }

        // 处理用户接收者
        if (recipients.getUsers() != null && !recipients.getUsers().isEmpty()) {
            for (Long userId : recipients.getUsers()) {
                // 验证用户是否存在
                userRepository.findById(userId)
                        .orElseThrow(() -> new RuntimeException("用户不存在: " + userId));

                NoticeRecipientEntity recipient = new NoticeRecipientEntity();
                recipient.setNoticeId(noticeId);
                recipient.setRecipientType("user");
                recipient.setTargetId(userId);
                recipient.setReadStatus(false);
                recipient.setCreatedAt(LocalDateTime.now());
                recipientList.add(recipient);
            }
        }

        // 处理角色接收者
        if (recipients.getRoles() != null && !recipients.getRoles().isEmpty()) {
            for (String role : recipients.getRoles()) {
                // 验证角色是否有效
                if (!isValidRole(role)) {
                    throw new RuntimeException("无效的角色: " + role);
                }

                NoticeRecipientEntity recipient = new NoticeRecipientEntity();
                recipient.setNoticeId(noticeId);
                recipient.setRecipientType("role");
                recipient.setTargetId((long) role.hashCode()); // 使用hashCode作为标识
                recipient.setReadStatus(false);
                recipient.setCreatedAt(LocalDateTime.now());
                recipientList.add(recipient);
            }
        }

        // 批量保存接收者
        if (!recipientList.isEmpty()) {
            noticeRecipientRepository.saveAll(recipientList);
        }
    }

    /**
     * 验证角色是否有效
     */
    private boolean isValidRole(String role) {
        return role != null && (role.equals("student") || role.equals("teacher") || role.equals("admin"));
    }

    /**
     * 转换实体为DTO
     */
    private NoticeDTO convertToDTO(NoticeEntity notice, Long userId, String tabType) {
        NoticeDTO dto = new NoticeDTO();
        dto.setNoticeId(notice.getNoticeId());
        dto.setTitle(notice.getTitle());
        dto.setTypeId(notice.getTypeId());
        dto.setDescription(notice.getDescription());
        dto.setContent(notice.getContent());
        dto.setScheduleId(notice.getScheduleId());
        dto.setCreateTime(notice.getCreatedAt());

        // 设置类型名称
        noticeTypeRepository.findById(notice.getTypeId()).ifPresent(type -> {
            dto.setTypeName(type.getTypeName());
        });

        // 设置发布者名称
        userRepository.findById(notice.getCreatedBy()).ifPresent(user -> {
            dto.setSenderName(user.getName());
        });

        if ("received".equals(tabType)) {
            // 对于接收方，设置阅读状态
            setReadStatusForReceiver(dto, notice.getNoticeId(), userId);
        } else {
            // 对于发布方，设置阅读统计和接收对象信息
            setStatisticsForPublisher(dto, notice.getNoticeId());
        }

        return dto;
    }

    /**
     * 设置接收方的阅读状态
     */
    private void setReadStatusForReceiver(NoticeDTO dto, Long noticeId, Long userId) {
        noticeRecipientRepository.findByNoticeIdAndUserId(noticeId, userId)
                .ifPresent(recipient -> {
                    dto.setReadStatus(recipient.getReadStatus());
                });
    }

    /**
     * 设置发布方的统计信息
     */
    private void setStatisticsForPublisher(NoticeDTO dto, Long noticeId) {
        Long readCount = noticeRecipientRepository.countReadRecipientsByNoticeId(noticeId);
        Long totalRecipients = noticeRecipientRepository.countTotalRecipientsByNoticeId(noticeId);

        dto.setReadCount(readCount != null ? readCount : 0L);
        dto.setTotalRecipients(totalRecipients != null ? totalRecipients : 0L);

        // 设置接收对象信息
        List<NoticeRecipientEntity> recipients = noticeRecipientRepository.findByNoticeId(noticeId);
        if (!recipients.isEmpty()) {
            dto.setRecipientInfo(generateRecipientInfo(recipients));
        }
    }

    /**
     * 生成接收对象信息
     */
    private String generateRecipientInfo(List<NoticeRecipientEntity> recipients) {
        if (recipients.size() == 1) {
            NoticeRecipientEntity recipient = recipients.get(0);
            return String.format("%s方式", recipient.getRecipientType());
        } else {
            long classCount = recipients.stream().filter(r -> "class".equals(r.getRecipientType())).count();
            long userCount = recipients.stream().filter(r -> "user".equals(r.getRecipientType())).count();
            long roleCount = recipients.stream().filter(r -> "role".equals(r.getRecipientType())).count();

            List<String> parts = new ArrayList<>();
            if (classCount > 0) parts.add(classCount + "个班级");
            if (userCount > 0) parts.add(userCount + "个用户");
            if (roleCount > 0) parts.add(roleCount + "种角色");

            return String.join("、", parts);
        }
    }
}
